{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 频率和周期处理\n",
    "\n",
    "本教程介绍Pandas中的频率字符串、自定义频率、工作日处理和节假日处理等功能。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from pandas.tseries.offsets import *\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 频率字符串详解"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基本频率代码\n",
    "basic_frequencies = {\n",
    "    'D': '日',\n",
    "    'W': '周（周日结束）',\n",
    "    'M': '月末',\n",
    "    'MS': '月初',\n",
    "    'Q': '季度末',\n",
    "    'QS': '季度初',\n",
    "    'Y': '年末',\n",
    "    'YS': '年初',\n",
    "    'H': '小时',\n",
    "    'T': '分钟',\n",
    "    'S': '秒',\n",
    "    'L': '毫秒',\n",
    "    'U': '微秒',\n",
    "    'N': '纳秒'\n",
    "}\n",
    "\n",
    "print(\"基本频率代码示例:\")\n",
    "base_date = '2023-06-15'\n",
    "for freq, desc in basic_frequencies.items():\n",
    "    try:\n",
    "        dates = pd.date_range(base_date, periods=3, freq=freq)\n",
    "        print(f\"{freq:2} ({desc:12}): {dates[0]} -> {dates[1]} -> {dates[2]}\")\n",
    "    except:\n",
    "        print(f\"{freq:2} ({desc:12}): 无法生成示例\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 工作日频率\n",
    "business_frequencies = {\n",
    "    'B': '工作日',\n",
    "    'BM': '工作日月末',\n",
    "    'BMS': '工作日月初',\n",
    "    'BQ': '工作日季度末',\n",
    "    'BQS': '工作日季度初',\n",
    "    'BY': '工作日年末',\n",
    "    'BYS': '工作日年初'\n",
    "}\n",
    "\n",
    "print(\"\\n工作日频率示例:\")\n",
    "for freq, desc in business_frequencies.items():\n",
    "    try:\n",
    "        dates = pd.date_range('2023-06-15', periods=3, freq=freq)\n",
    "        print(f\"{freq:3} ({desc:10}): {dates[0].strftime('%Y-%m-%d %a')} -> {dates[1].strftime('%Y-%m-%d %a')} -> {dates[2].strftime('%Y-%m-%d %a')}\")\n",
    "    except:\n",
    "        print(f\"{freq:3} ({desc:10}): 无法生成示例\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自定义频率倍数\n",
    "custom_frequencies = {\n",
    "    '2D': '每2天',\n",
    "    '3W': '每3周',\n",
    "    '2M': '每2个月',\n",
    "    '6H': '每6小时',\n",
    "    '30T': '每30分钟',\n",
    "    '15S': '每15秒',\n",
    "    '2B': '每2个工作日'\n",
    "}\n",
    "\n",
    "print(\"\\n自定义频率倍数示例:\")\n",
    "for freq, desc in custom_frequencies.items():\n",
    "    try:\n",
    "        dates = pd.date_range('2023-06-15 09:00:00', periods=3, freq=freq)\n",
    "        print(f\"{freq:3} ({desc:10}): {dates[0]} -> {dates[1]}\")\n",
    "    except:\n",
    "        print(f\"{freq:3} ({desc:10}): 无法生成示例\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 高级频率和偏移"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用DateOffset类\n",
    "base_date = pd.Timestamp('2023-06-15')\n",
    "\n",
    "print(\"DateOffset示例:\")\n",
    "print(f\"基准日期: {base_date}\")\n",
    "\n",
    "# 各种偏移\n",
    "offsets = {\n",
    "    'Day(1)': Day(1),\n",
    "    'Week(1)': Week(1),\n",
    "    'MonthEnd(1)': MonthEnd(1),\n",
    "    'MonthBegin(1)': MonthBegin(1),\n",
    "    'QuarterEnd(1)': QuarterEnd(1),\n",
    "    'YearEnd(1)': YearEnd(1),\n",
    "    'BusinessDay(1)': BusinessDay(1),\n",
    "    'Hour(6)': Hour(6)\n",
    "}\n",
    "\n",
    "for name, offset in offsets.items():\n",
    "    result = base_date + offset\n",
    "    print(f\"{name:15} -> {result}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 特定星期几的频率\n",
    "print(\"特定星期几的频率:\")\n",
    "\n",
    "# 每周一\n",
    "mondays = pd.date_range('2023-06-01', '2023-06-30', freq='W-MON')\n",
    "print(f\"六月的周一: {mondays.tolist()}\")\n",
    "\n",
    "# 每周五\n",
    "fridays = pd.date_range('2023-06-01', '2023-06-30', freq='W-FRI')\n",
    "print(f\"六月的周五: {fridays.tolist()}\")\n",
    "\n",
    "# 每月第三个周五\n",
    "third_fridays = pd.date_range('2023-01-01', '2023-12-31', freq='WOM-3FRI')\n",
    "print(f\"\\n2023年每月第三个周五: {third_fridays.tolist()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 自定义工作日历"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建自定义工作日历\n",
    "from pandas.tseries.holiday import USFederalHolidayCalendar, Holiday\n",
    "from datetime import date\n",
    "\n",
    "# 使用美国联邦假日日历\n",
    "us_calendar = USFederalHolidayCalendar()\n",
    "us_holidays = us_calendar.holidays(start='2023-01-01', end='2023-12-31')\n",
    "\n",
    "print(\"2023年美国联邦假日:\")\n",
    "for holiday in us_holidays:\n",
    "    print(f\"  {holiday.strftime('%Y-%m-%d %A')}: {us_calendar.rules[us_holidays.get_loc(holiday)].name}\")\n",
    "\n",
    "# 创建考虑假日的工作日序列\n",
    "business_days_with_holidays = pd.bdate_range(\n",
    "    start='2023-01-01', \n",
    "    end='2023-01-31',\n",
    "    holidays=us_holidays\n",
    ")\n",
    "\n",
    "print(f\"\\n2023年1月工作日（排除假日）数量: {len(business_days_with_holidays)}\")\n",
    "print(f\"前10个工作日: {business_days_with_holidays[:10].tolist()}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 自定义假日\n",
    "# 定义中国的一些假日\n",
    "chinese_holidays = [\n",
    "    Holiday('元旦', month=1, day=1),\n",
    "    Holiday('劳动节', month=5, day=1),\n",
    "    Holiday('国庆节', month=10, day=1),\n",
    "    Holiday('国庆节2', month=10, day=2),\n",
    "    Holiday('国庆节3', month=10, day=3)\n",
    "]\n",
    "\n",
    "# 创建自定义日历\n",
    "from pandas.tseries.holiday import AbstractHolidayCalendar\n",
    "\n",
    "class ChineseHolidayCalendar(AbstractHolidayCalendar):\n",
    "    rules = chinese_holidays\n",
    "\n",
    "chinese_cal = ChineseHolidayCalendar()\n",
    "chinese_holidays_2023 = chinese_cal.holidays(start='2023-01-01', end='2023-12-31')\n",
    "\n",
    "print(\"\\n自定义中国假日:\")\n",
    "for holiday in chinese_holidays_2023:\n",
    "    print(f\"  {holiday.strftime('%Y-%m-%d %A')}\")\n",
    "\n",
    "# 创建考虑中国假日的工作日\n",
    "chinese_business_days = pd.bdate_range(\n",
    "    start='2023-10-01',\n",
    "    end='2023-10-10', \n",
    "    holidays=chinese_holidays_2023\n",
    ")\n",
    "\n",
    "print(f\"\\n2023年10月1-10日工作日（排除国庆假期）: {chinese_business_days.tolist()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 周期性数据分析"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建包含周期性模式的数据\n",
    "np.random.seed(42)\n",
    "dates = pd.date_range('2023-01-01', '2023-12-31', freq='D')\n",
    "\n",
    "# 模拟包含多种周期的数据\n",
    "# 年度趋势\n",
    "annual_trend = np.linspace(100, 150, len(dates))\n",
    "\n",
    "# 季节性（年周期）\n",
    "seasonal_annual = 20 * np.sin(2 * np.pi * np.arange(len(dates)) / 365.25)\n",
    "\n",
    "# 周周期\n",
    "weekly_pattern = 10 * np.sin(2 * np.pi * np.arange(len(dates)) / 7)\n",
    "\n",
    "# 月周期\n",
    "monthly_pattern = 5 * np.sin(2 * np.pi * np.arange(len(dates)) / 30.44)\n",
    "\n",
    "# 随机噪声\n",
    "noise = np.random.normal(0, 5, len(dates))\n",
    "\n",
    "# 合成数据\n",
    "synthetic_data = annual_trend + seasonal_annual + weekly_pattern + monthly_pattern + noise\n",
    "\n",
    "ts_data = pd.Series(synthetic_data, index=dates)\n",
    "\n",
    "print(\"合成周期性数据统计:\")\n",
    "print(ts_data.describe())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 分析不同周期的模式\n",
    "# 按月份分析\n",
    "monthly_pattern_analysis = ts_data.groupby(ts_data.index.month).agg(['mean', 'std'])\n",
    "print(\"月度模式分析:\")\n",
    "print(monthly_pattern_analysis.round(2))\n",
    "\n",
    "# 按星期分析\n",
    "weekly_pattern_analysis = ts_data.groupby(ts_data.index.dayofweek).agg(['mean', 'std'])\n",
    "weekly_pattern_analysis.index = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']\n",
    "print(\"\\n周度模式分析:\")\n",
    "print(weekly_pattern_analysis.round(2))\n",
    "\n",
    "# 按季度分析\n",
    "quarterly_pattern_analysis = ts_data.groupby(ts_data.index.quarter).agg(['mean', 'std'])\n",
    "print(\"\\n季度模式分析:\")\n",
    "print(quarterly_pattern_analysis.round(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. 频率转换和重采样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 频率转换示例\n",
    "print(\"频率转换示例:\")\n",
    "\n",
    "# 日数据转周数据\n",
    "weekly_data = ts_data.resample('W').mean()\n",
    "print(f\"原始日数据点数: {len(ts_data)}\")\n",
    "print(f\"转换后周数据点数: {len(weekly_data)}\")\n",
    "\n",
    "# 日数据转月数据\n",
    "monthly_data = ts_data.resample('M').agg({\n",
    "    'mean': 'mean',\n",
    "    'max': 'max',\n",
    "    'min': 'min',\n",
    "    'std': 'std'\n",
    "})\n",
    "\n",
    "print(\"\\n月度汇总数据:\")\n",
    "print(monthly_data.head())\n",
    "\n",
    "# 不同频率的重采样\n",
    "resampling_examples = {\n",
    "    'W': '周',\n",
    "    'M': '月',\n",
    "    'Q': '季度',\n",
    "    'Y': '年'\n",
    "}\n",
    "\n",
    "print(\"\\n不同频率重采样结果:\")\n",
    "for freq, desc in resampling_examples.items():\n",
    "    resampled = ts_data.resample(freq).mean()\n",
    "    print(f\"{desc:4} ({freq}): {len(resampled):3}个数据点, 平均值: {resampled.mean():.2f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 实际应用示例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模拟零售业务数据分析\n",
    "np.random.seed(42)\n",
    "\n",
    "# 创建2年的日销售数据\n",
    "business_dates = pd.bdate_range('2022-01-01', '2023-12-31')\n",
    "\n",
    "# 模拟销售数据（考虑各种周期性因素）\n",
    "base_sales = 10000\n",
    "\n",
    "# 年度增长趋势\n",
    "growth_trend = np.linspace(1.0, 1.2, len(business_dates))\n",
    "\n",
    "# 季节性因素（年末购物季）\n",
    "seasonal_factor = 1 + 0.3 * np.sin(2 * np.pi * (business_dates.dayofyear - 60) / 365) + \\\n",
    "                 0.5 * (business_dates.month == 12).astype(float)  # 12月促销\n",
    "\n",
    "# 周末效应（周五周六销量更高）\n",
    "weekend_factor = 1 + 0.2 * (business_dates.dayofweek >= 4).astype(float)\n",
    "\n",
    "# 月初月末效应（发薪日效应）\n",
    "payroll_factor = 1 + 0.1 * ((business_dates.day <= 5) | (business_dates.day >= 25)).astype(float)\n",
    "\n",
    "# 随机波动\n",
    "random_factor = 1 + np.random.normal(0, 0.1, len(business_dates))\n",
    "\n",
    "# 合成销售数据\n",
    "sales = base_sales * growth_trend * seasonal_factor * weekend_factor * payroll_factor * random_factor\n",
    "\n",
    "sales_df = pd.DataFrame({\n",
    "    'sales': sales,\n",
    "    'date': business_dates\n",
    "})\n",
    "sales_df.set_index('date', inplace=True)\n",
    "\n",
    "print(\"零售销售数据统计:\")\n",
    "print(sales_df.describe())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 多频率分析\n",
    "print(\"多频率销售分析:\")\n",
    "\n",
    "# 周度分析\n",
    "weekly_sales = sales_df.resample('W').agg({\n",
    "    'total': 'sum',\n",
    "    'average': 'mean',\n",
    "    'days': 'count'\n",
    "})\n",
    "\n",
    "# 月度分析\n",
    "monthly_sales = sales_df.resample('M').agg({\n",
    "    'total': 'sum',\n",
    "    'average': 'mean',\n",
    "    'max_day': 'max',\n",
    "    'min_day': 'min',\n",
    "    'days': 'count'\n",
    "})\n",
    "\n",
    "# 季度分析\n",
    "quarterly_sales = sales_df.resample('Q').agg({\n",
    "    'total': 'sum',\n",
    "    'average': 'mean',\n",
    "    'growth': lambda x: (x.iloc[-1] - x.iloc[0]) / x.iloc[0] * 100 if len(x) > 1 else 0\n",
    "})\n",
    "\n",
    "print(\"\\n季度销售汇总:\")\n",
    "print(quarterly_sales.round(2))\n",
    "\n",
    "print(\"\\n月度销售汇总（2023年）:\")\n",
    "print(monthly_sales['2023'].round(2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 周期性模式识别\n",
    "# 按星期几分析\n",
    "weekday_analysis = sales_df.groupby(sales_df.index.dayofweek)['sales'].agg(['mean', 'std'])\n",
    "weekday_analysis.index = ['周一', '周二', '周三', '周四', '周五']\n",
    "\n",
    "print(\"工作日销售模式:\")\n",
    "print(weekday_analysis.round(2))\n",
    "\n",
    "# 按月份分析\n",
    "monthly_pattern = sales_df.groupby(sales_df.index.month)['sales'].agg(['mean', 'std'])\n",
    "month_names = ['1月', '2月', '3月', '4月', '5月', '6月', \n",
    "               '7月', '8月', '9月', '10月', '11月', '12月']\n",
    "monthly_pattern.index = month_names\n",
    "\n",
    "print(\"\\n月度销售模式:\")\n",
    "print(monthly_pattern.round(2))\n",
    "\n",
    "# 找出销售最好和最差的月份\n",
    "best_month = monthly_pattern['mean'].idxmax()\n",
    "worst_month = monthly_pattern['mean'].idxmin()\n",
    "\n",
    "print(f\"\\n销售最好的月份: {best_month} (平均: {monthly_pattern.loc[best_month, 'mean']:.0f})\")\n",
    "print(f\"销售最差的月份: {worst_month} (平均: {monthly_pattern.loc[worst_month, 'mean']:.0f})\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 可视化不同频率的数据\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 10))\n",
    "\n",
    "# 原始日销售数据（2023年）\n",
    "sales_df['2023']['sales'].plot(ax=axes[0,0], title='2023年日销售数据')\n",
    "axes[0,0].set_ylabel('销售额')\n",
    "\n",
    "# 周销售数据\n",
    "weekly_sales['2023']['total'].plot(ax=axes[0,1], title='2023年周销售总额', marker='o')\n",
    "axes[0,1].set_ylabel('销售额')\n",
    "\n",
    "# 月销售数据\n",
    "monthly_sales['total'].plot(ax=axes[1,0], title='月销售总额', marker='s')\n",
    "axes[1,0].set_ylabel('销售额')\n",
    "\n",
    "# 工作日模式\n",
    "weekday_analysis['mean'].plot(kind='bar', ax=axes[1,1], title='工作日平均销售额')\n",
    "axes[1,1].set_ylabel('销售额')\n",
    "axes[1,1].tick_params(axis='x', rotation=45)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
